﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics.Contracts;
using System.Linq;
using System.Text;

namespace Cloak.Mvp
{
	/// <summary>
	/// The presentation of a view in the form of a set of presenters
	/// </summary>
	public class ViewPresentation
	{
		private static readonly ReadOnlyCollection<IPresenterReference>
			_emptyPresenters = Enumerable.Empty<IPresenterReference>().ToList().AsReadOnly();

		/// <summary>
		/// Initializes a presentation with no presenters
		/// </summary>
		public ViewPresentation()
		{
			Presenters = _emptyPresenters;
		}

		/// <summary>
		/// Initializes a presentation with the specified presenters
		/// </summary>
		/// <param name="presenters">The presenters to bind to the view</param>
		public ViewPresentation(IEnumerable<IPresenterReference> presenters)
		{
			Contract.Requires(presenters != null);

			Presenters = presenters.ToList().AsReadOnly();
		}

		/// <summary>
		/// Initializes a presentation with the specified presenters
		/// </summary>
		/// <param name="presenters">The presenters to bind to the view</param>
		/// <param name="replaceDeclaredPresenters">
		/// Gets whether <paramref name="presenters"/> replaces the presenters declared for the view
		/// </param>
		public ViewPresentation(IEnumerable<IPresenterReference> presenters, bool replaceDeclaredPresenters)
			: this(presenters)
		{
			ReplaceDeclaredPresenters = replaceDeclaredPresenters;
		}

		/// <summary>
		/// Gets the presenters to bind to the view
		/// </summary>
		public ReadOnlyCollection<IPresenterReference> Presenters { get; private set; }

		/// <summary>
		/// Gets whether <see cref="Presenters"/> replaces the presenters declared for the view
		/// </summary>
		public bool ReplaceDeclaredPresenters { get; private set; }

		/// <summary>
		/// Creates a new presentation by appending the specified presenters
		/// </summary>
		/// <param name="presenters">The presenters to be appended</param>
		/// <returns>A new presentation with the specified presenters appended</returns>
		public ViewPresentation WithPresenters(IEnumerable<IPresenterReference> presenters)
		{
			Contract.Requires(presenters != null);

			return new ViewPresentation(Presenters.Concat(presenters), ReplaceDeclaredPresenters);
		}

		/// <summary>
		/// Creates a new presentation by appending the specified presenters
		/// </summary>
		/// <param name="presenters">The presenters to be appended</param>
		/// <returns>A new presentation with the specified presenters appended</returns>
		public ViewPresentation WithPresenters(params IPresenterReference[] presenters)
		{
			return WithPresenters(presenters as IEnumerable<IPresenterReference>);
		}

		/// <summary>
		/// Creates a presentation by appending the presenter of the specified type
		/// </summary>
		/// <param name="type">The type of presenter to append</param>
		/// <returns>A new presentation with the specified presenter type appended</returns>
		public ViewPresentation WithPresenter(Type type)
		{
			Contract.Requires(type != null);

			return WithPresenters(new PresenterReference(type));
		}

		/// <summary>
		/// Creates a new presentation by appending the presenter of the specified type
		/// </summary>
		/// <typeparam name="T">The type of presenter to append</typeparam>
		/// <returns>A new presentation with the specified presenter type appended</returns>
		public ViewPresentation WithPresenter<T>()
		{
			return WithPresenter(typeof(T));
		}
	}
}